import { TrackOpType } from "./const"
import { effect, track } from "./effect"
import { isFunction } from "./utils"


interface ComputedOption<T> {
  get?():T
  set?(newValue:T):void
}

class ComputedRefImpl<T> {
  private dirty:boolean = true
  private _value:T|undefined

  constructor(
    private getter:()=>T, 
    private setter:(v:T)=>void, 
    private effect:Function) {

  }

  get value() {
    if(this.dirty) {
      this._value = this.getter()
      this.dirty = false
    }

    track(this, TrackOpType.GET, 'value')

    return this._value as T
  }

  set value(newValue:T) {
    this.setter(newValue)
  }
}

export function computed<T>(getter:()=>T):ComputedRefImpl<T>
export function computed<T>(option:ComputedOption<T>):ComputedRefImpl<T>
export function computed<T>(getterOrOption:(()=>T)|ComputedOption<T>) {
  let get:()=>T, 
    set:(v:T)=>void

  if(isFunction(getterOrOption)) {
    get = getterOrOption as ()=>T
    set = ()=>console.warn('computed is readonly!')
  } else {
    ({ get, set } = getterOrOption as any)
  }

  const runner = effect(get, {
    lazy:true,
    computed: true,
    scheduler() {
        
    }
  })
  
  return new ComputedRefImpl<T>(get, set, runner)
}
